#pragma once

#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <map>
#include <vector>
#include "../Math/RetroMath.h"
#include "../WiiYourself/wiimote.h"

#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")

enum InputDevices { RZ_MOUSE = 1, RZ_KEYBOARD = 2, RZ_WIIMOTE = 4, RZ_NUNCHUCK};
enum ButtonState { BTN_PRESSED, BTN_RELEASED, BTN_HELD};
enum MouseButtons { MOUSE_LEFT = 0, MOUSE_RIGHT, MOUSE_CENTER};
enum ButtonAction { ACTION_UP, ACTION_DOWN, ACTION_LEFT, ACTION_RIGHT,
					ACTION_FIRE, ACTION_CENTER_CURSOR}; // Add actions like walk, attack, etc
enum ButtonBitMasks 
{
	WII_BTN_LEFT		= 0x0001,
	WII_BTN_RIGHT		= 0x0002,
	WII_BTN_DOWN		= 0x0004,
	WII_BTN_UP			= 0x0008,
	WII_BTN_PLUS		= 0x0010,
	UNUSED_BIT_20		= 0x0020, // unused
	UNUSED_BIT_10		= 0x0040, // unused
	UNUSED_BIT_80		= 0x0080, // unused
	WII_BTN_TWO			= 0x0100,
	WII_BTN_ONE			= 0x0200,
	WII_BTN_B			= 0x0400,	
	WII_BTN_A			= 0x0800,
	WII_BTN_MINUS		= 0x1000,
	WII_BTN_NUNCHUCK_C	= 0x2000, // placed for nunchuck
	WII_BTN_NUNCHUCK_Z	= 0x4000, // placed for nunchuck
	WII_BTN_HOME		= 0x8000,
}; // fits in the wiimote state bits

class CRetroInput
{
private: // singleton
	CRetroInput(void);
	~CRetroInput(void);
	CRetroInput(const CRetroInput&);
	CRetroInput& operator=(const CRetroInput&);
	static CRetroInput* m_pInstance;
public: // singleton
	static CRetroInput* GetInstance() { if(m_pInstance == NULL) m_pInstance = new CRetroInput; return m_pInstance;}
	static void FreeInstance() { CRetroInput::m_pInstance->Shutdown(); delete CRetroInput::m_pInstance; CRetroInput::m_pInstance = NULL;}
private:
	BYTE m_DevicesInUse;

	IDirectInput8* m_pInput;
	IDirectInputDevice8* m_pKeyboard;
	IDirectInputDevice8* m_pMouse;

	BYTE m_keyboardState[256];
	BYTE m_prevKeyboardState[256];
	DIMOUSESTATE m_mouseState;
	DIMOUSESTATE m_prevMouseState;
	// WORD m_wiimoteState;
	// WORD m_prevWiimoteState;

	wiimote m_Wiimote;
	static void wiiremote_callback(wiimote &remote, state_change_flags changed, const wiimote_state &new_state);

	struct ActionData
	{
		ButtonState state;
		UINT keycode;
	};
	std::map<ButtonAction, std::map<InputDevices, ActionData>>  m_ActionMap;

	bool CheckMouseState(ActionData &data);
	bool CheckKeyboardState(ActionData &data);
	bool CheckWiimoteState(ActionData &data);

	vec3<float> m_vfMotionPlusDelta;
	vec3<float> m_vfMotionPlusCalibrationOffset;

public:
	WORD m_wiimoteState;
	WORD m_prevWiimoteState;

	bool Init(HWND hWnd, HINSTANCE hInstance, BYTE deviceFlags, BYTE exclusiveFlags = 0);
	void Shutdown();
	void Update();
		
	void RegisterAction(ButtonAction actionID, InputDevices actionDevice, ButtonState actionState, UINT keycode);
	void UnRegisterAction(ButtonAction actionID, InputDevices actionDevice);
	bool CheckAction(ButtonAction actionID);

	bool KeyHeld(UINT keycode);
	bool KeyPressed(UINT keycode);
	bool KeyReleased(UINT keycode);

	vec3<long> GetMouseDelta();
	bool MouseHeld(UINT keycode);
	bool MousePressed(UINT keycode);
	bool MouseReleased(UINT keycode);
		
	vec3<float> GetWiiAccelerometerDelta();
	vec3<float> GetWiiMotionPlusDelta(bool bOffset = true);
	void SetMotionPlusCalibrationOffset(float X, float Y, float Z);
	void SetMotionPlusCalibrationOffset(vec3<float>& offset);
	bool WiiKeyHeld(UINT keycode);
	bool WiiKeyPressed(UINT keycode);
	bool WiiKeyReleased(UINT keycode);
};